package gbench.tartarus.hipponoe.mvc;

import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {

    /**
     * @param className
     * @return
     */
    public static Class<?> forName(String className) {
        try {
            return Class.forName(className.replaceAll("/|\\\\", "."));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取所有文件列表
     *
     * @param rootFile
     * @param fileList
     * @return class 文件名，不带有class后缀
     * @throws IOException
     */
    public static List<String> listClasses(File rootFile, List<String> fileList) throws IOException {
        final var rootPath = rootFile.getPath();
        if (!(rootPath.contains(".war") || rootPath.contains(".jar"))) {
            final var allFiles = rootFile.listFiles();
            for (File file : allFiles) {
                if (file.isDirectory()) {
                    listClasses(file, fileList);
                } else {
                    final var path = file.getCanonicalPath();
                    final var clazz = path.substring(path.indexOf("classes") + 8);
                    fileList.add(clazz.replace("//", ".")
                            .substring(0, clazz.lastIndexOf(".")));
                }//if
            }//for
        } else { // 读取jar文件 获取class文件
            final var ss = rootPath.split("!"); // 文件分段
            final var jarFile = new JarFile(new File(ss[0].substring("file:/".length())));
            final var pkgName = ss[ss.length - 1].substring(1).replace(File.separator, "/");

            jarFile.stream().map(JarEntry::getRealName).filter(e -> e.contains(pkgName)).map(line -> {
                return line.substring(line.indexOf(pkgName));
            }).filter(e -> e.endsWith(".class")).map(e -> {
                return e.replace("/", ".").substring(0, e.length() - ".class".length());
            }).forEach(fileList::add);
        } // if war,jar 文件的检测

        return fileList;
    }

    /**
     * 获取子类型
     *
     * @param baseClazz 基本类型
     * @param cs        回调函数
     */
    public void handleAllSubClasses(final String pkgname, final Class<?> baseClazz, final Consumer<Class<?>> cs) {
        final var rootPath = this.getClass().getClassLoader().getResource(pkgname).getFile();
        final var rootFile = new File(rootPath.replace("%20", " "));

        if (rootFile == null) return;
        try {
            listClasses(rootFile, new LinkedList<String>()).stream()
                .map(MvcConfig::forName)
                .filter(e -> e != null)
                .filter(baseClazz::isAssignableFrom)
                .forEach(cs);
        } catch (Exception e) {
            e.printStackTrace();
        }// try
    }

    /**
     * 参数处理子
     */
    @Override
    public void addArgumentResolvers(final List<HandlerMethodArgumentResolver> resolvers) {
        final var pkgName = this.getClass().getPackageName().replace('.', '/'); // 提取当前目录下的 resolver class
        handleAllSubClasses(pkgName, HandlerMethodArgumentResolver.class, clazz -> {
            try {
                final var ctor = clazz.getConstructor();
                final var resolver = (HandlerMethodArgumentResolver) ctor.newInstance();
                if (resolver == null) return;
                resolvers.add(resolver);
            } catch (Exception e) {
                e.printStackTrace();
            }// try
        });
    }
}